// array indexes for the _signal arrays
const int OFF = -1; // not a valid array index, used as a flag
const int GREEN = 0;
const int YELLOW = 1;
const int RED = 2;

// BA - was the idea here to add an extra light to each signal? You would also need to change the two arrays below, making them size 4 instead of 3.
//      then you would use the fourth array slot to indicate which pin # the white light was hooked up to.
const int WHITE = 3;  // mike 6-29

// arduino pin numbers for each LED: green, yellow, red
int north_south_signal[3] = {5, 6, 7};
int east_west_signal[3] = {8, 9, 10};

// BA - it's not clear to me what these extra pins would be hooked up to. More lights?
int north_south_ped = 11; // mike 6-29
int east_west_ped = 12;  // mike 6-29

// interrupt number for the clock
int clock_interrupt = 0;
// interrupt number for the button
int flash_button_interrupt = 1;

// array indexes used for the signal_states array
const int NORTH_SOUTH = 0;
const int EAST_WEST = 1;

// this holds all the possible light combinations
// first column is the north/south signal, second is the east/west signal
int signal_states[8][2] = {
  {GREEN,RED},
  {YELLOW,RED},
  {RED,RED},
  {RED,GREEN},
  {RED,YELLOW},
  {RED,RED},  
  {RED, YELLOW},  // mike 6-29 
  
  // BA - if you were to pass WHITE to the change_light() function, it wouldn't know what to do (and in fact right now it would crash).
  //      up above I talked about what's needed to add a another light color to the signals.
  {WHITE, WHITE}  // mike 6-29
};

// start at the last state so it will loop back to the beginning
volatile int current_state = 5;
// flag that indicates that the button has been pressed
volatile int flash_mode = 0;
// timestamp in millis when the button was pressed. used for debouncing.
volatile int flash_button_press = 0;

// counts every tick since the system started
volatile long all_ticks = 0;
// counts the ticks since the last state change
volatile long state_ticks = 0;

// change intervals in seconds
int Min_Green = 9;
int Yellow_Change = 3;
int Red_Clear = 1;
int Flash_Interval = 1;

void tick() {
  all_ticks++;
  state_ticks++;
  
  if (flash_mode) {
    if (state_ticks == Flash_Interval) flash_signals();
    return; // exit the function immediately
  }
  
  // BA - I think you tried to copy the way I implemented flash_mode. But if you want to use the signal_states array for this,
  //      you are better off expanding on the switch block below.
//if (night_time) {  // mike 6-29
//  if (all_ticks >= 200) night_flash();  // mike 6-29
//  return;  // mike 6-29
//}  // mike 6-29 
  
  // BA - the modulus was a shortcut, but it made this switch block non-expandable to handle more states.
  //      so I added an explicit case line for each value of current_state.
  switch (current_state) {
    case 0:
      if (state_ticks >= Min_Green) next_state();
      break;
    case 1:
      if (state_ticks >= Yellow_Change) next_state();
      break;    
    case 2:
      if (state_ticks >= Red_Clear) next_state();
      break;
    case 3:
      if (state_ticks >= Min_Green) next_state();
      break;
    case 4:
      if (state_ticks >= Yellow_Change) next_state();
      break;    
    case 5:
      if (state_ticks >= Red_Clear) next_state();
      break;
    case 6:
      // BA - this is the first state you added, the {RED,YELLOW}.
      //    - How does it know if it should do something? (do you check state_ticks? all_ticks? some other variable?)
      //    - What should it do? (i.e. what function does it call)
      //    - Which state does it advance to from here? (how do you update current_state and where do you do it)
      break;
    case 7:
      // BA - this is the second state you added, the {WHITE,WHITE}. Same questions as above.
      break;
  }
}

void change_light(int *signal, int current_light, int new_light) {
  if (current_light != new_light) {
    if (current_light != OFF) digitalWrite(signal[current_light], LOW);
    if (new_light != OFF) digitalWrite(signal[new_light], HIGH);
  }
}


// switches off all 3 lights, used to make sure we are in a consistent state
void signal_off(int *signal) {
  digitalWrite(signal[GREEN], LOW);
  digitalWrite(signal[YELLOW], LOW);
  digitalWrite(signal[RED], LOW);
}

void next_state() {
  // BA - the modulus means this function will only ever set current_state to 0 through 5, in the same order every time.
  //    - if you wanted it to reach states 6 or 7, or change the logic to advance in a different order, this line would need to change.
  int new_state = (current_state+1) % 6;
  
  // figure out which light is currently lit on the N/S signal, and which one needs to be lit next
  int current_north_south = signal_states[current_state][NORTH_SOUTH];
  int new_north_south = signal_states[new_state][NORTH_SOUTH];
  
  // if they aren't equal, the N/S light needs to change
  change_light(north_south_signal, current_north_south, new_north_south);

  // this is identical to the section above, just using the E/W signal
  int current_east_west = signal_states[current_state][EAST_WEST];
  int new_east_west = signal_states[new_state][EAST_WEST];

  change_light(east_west_signal, current_east_west, new_east_west);
  
  // after we've changed all the lights, update the current state
  current_state = new_state;
  state_ticks = 0;
}


// called when flash_mode is true
// flashes both signals between OFF and RED or YELLOW
void flash_signals() {
  if (current_state == OFF) {
    change_light(north_south_signal, OFF, RED);
    change_light(east_west_signal, OFF, YELLOW);
    current_state = RED;
  } else {
    change_light(north_south_signal, RED, OFF);
    change_light(east_west_signal, YELLOW, OFF);
    current_state = OFF;
  }
  state_ticks = 0;
}

void night_flash() {  // mike 6-29
}


// this is the interrupt service routine for the button
// toggles the flash_mode variable between 0 and 1
// uses a 300ms delay to prevent bouncing
void flash_toggle_button() {
  int debounce = 300;
  if( abs(millis()-flash_button_press) < debounce) return;
  flash_button_press = millis();
  
  if (flash_mode) {
    flash_mode = 0;
    init_signal_sequence();
  } else {
    flash_mode = 1;
    init_flash_sequence();
  }  
}


// any time we switch from one state to another, blank all the lights
// and inititalize variables so we start from a consistent state each time
void init_signal_sequence() {
  current_state = 5;
  signal_off(north_south_signal);
  signal_off(east_west_signal);
  change_light(north_south_signal, OFF, signal_states[current_state][NORTH_SOUTH]);
  change_light(east_west_signal, OFF, signal_states[current_state][EAST_WEST]);
  state_ticks = 0;
}
void init_flash_sequence() {
    signal_off(north_south_signal);
    signal_off(east_west_signal);
    current_state = OFF;
    state_ticks = 0;
}


void setup() {
  noInterrupts();

  pinMode(north_south_signal[GREEN], OUTPUT);
  pinMode(north_south_signal[YELLOW], OUTPUT);
  pinMode(north_south_signal[RED], OUTPUT);
  
  pinMode(east_west_signal[GREEN], OUTPUT);
  pinMode(east_west_signal[YELLOW], OUTPUT);
  pinMode(east_west_signal[RED], OUTPUT);
  
  // BA - it's not clear to me what these extra pins would be hooked up to. More lights? You don't write to them anywhere that I can see.
  pinMode(north_south_ped, OUTPUT);  // mike 6-29
  pinMode(east_west_ped, OUTPUT);  // mike 6-29


  attachInterrupt(clock_interrupt, tick, RISING);
  attachInterrupt(flash_button_interrupt, flash_toggle_button, RISING);
  
  // force the lights to initialize
  init_signal_sequence();
  
  interrupts();
}


void loop() {

}





